﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Tsanie.OsuDevice.Utils;
using Tsanie.OsuDevice.Network;
using Tsanie.OsuDevice.Components;
using System.IO;
using Tsanie.OsuDevice.Models;
using System.Threading;
using ICSharpCode.SharpZipLib.Zip;

namespace Tsanie.OsuDevice {
    public partial class MainForm : Form {
        internal ITaskbarList3 taskbarItem = null;
        internal bool isRunning = false;
        private Tsanie.OsuDevice.Components.ListView listNow = null;

        private int totalLength = 0;

        #region - 窗体 -
        public MainForm() {
            InitializeComponent();
            this.Icon = Tsanie.OsuDevice.Properties.Resources.AppIcon;
            this.Text = Config.c_AppTitle;
            listBeatmapWeb.MouseWheel += new MouseEventHandler(listBeatmapWeb_MouseWheel);
            treeNagetive.GotFocus += new EventHandler(treeNagetive_GotFocus);
            listBeatmapLocal.GotFocus += new EventHandler(listBeatmap_GotFocus);
            listBeatmapWeb.GotFocus += new EventHandler(listBeatmap_GotFocus);
            for (int i = 0; i < 4; i++) {
                ListViewImage.SetColumnHeaderImageList(listBeatmapLocal, i, imageTree);
                ListViewImage.SetColumnHeaderImageList(listBeatmapWeb, i, imageTree);
            }
            ListViewImage.SetColumnHeaderSorter(listBeatmapLocal, new SubItemSorter(3, false, 2));
        }

        private void MainForm_Load(object sender, EventArgs e) {
            if (VistaStuff.IsVistaOrNot) {
                VistaStuff.SetWindowTheme(listBeatmapLocal.Handle, "explorer", null);
                VistaStuff.SetWindowTheme(listBeatmapWeb.Handle, "explorer", null);
                VistaStuff.SetWindowTheme(treeNagetive.Handle, "explorer", null);
            }
            listNow = listBeatmapLocal;
            TreeNode nodeLibrary = treeNagetive.Nodes["nodeLibrary"];
            nodeLibrary.Expand();
            treeNagetive.SelectedNode = nodeLibrary.Nodes["nodeLibraryLocal"];
            treeNagetive.Nodes["nodeManager"].Expand();
            toolComboType.SelectedIndex = 0;
        }
        private void MainForm_Shown(object sender, EventArgs e) {
            if (VistaStuff.IsWin7)
                taskbarItem = (ITaskbarList3)new ProgressTaskbar();
            MainForm_Resize(sender, e);
            EnabledControl(true);
            RefreshLocal("\\beatmaps.txt", listBeatmapLocal);
        }
        internal void MainForm_Resize(object sender, EventArgs e) {
            toolStrip.Width = this.ClientSize.Width - 6;
            toolStatus.Width = (this.toolProgress.Visible ? this.ClientSize.Width - 184 : this.ClientSize.Width - 44);
        }
        #endregion

        #region - 事件 -
        private void menuLogin_Click(object sender, EventArgs e) {
            new LoginForm().ShowDialog(this);
        }
        private void menuLogout_Click(object sender, EventArgs e) {
            Config.Cookies = null;
            EnabledControl(toolOption.Enabled);
        }
        private void menuDownload_Click(object sender, EventArgs e) {
            if (listNow == null || listNow != listBeatmapWeb)
                return;
            foreach (ListViewItem lvi in listBeatmapWeb.SelectedItems) {
                Beatmap bm = (Beatmap)lvi.Tag;
                if (!Directory.Exists(Config.DownloadPath))
                    Directory.CreateDirectory(Config.DownloadPath);
                DownloadItem item = listDownloader.AddDownload(bm.Title, lvi);
                DownloadBeatmap(bm.MapID, item, Config.DownloadPath);
            }
            TreeNode node = treeNagetive.Nodes["nodeManager"].FirstNode;
            treeNagetive.SelectedNode = node;
            treeNagetive_AfterSelect(sender, new TreeViewEventArgs(node, TreeViewAction.ByMouse));
            TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_INDETERMINATE);
        }
        private void menuOption_Click(object sender, EventArgs e) {
            new OptionForm().ShowDialog(this);
        }
        private void menuExit_Click(object sender, EventArgs e) {
            isRunning = false;
            Application.Exit();
        }
        private void menuRefresh_Click(object sender, EventArgs e) {
            TreeNode node = treeNagetive.SelectedNode;
            switch (node.Name) {
                case "nodeLibraryWeb":
                    RefreshWeb();
                    break;
                default:
                    Refresher();
                    break;
            }
        }

        private void listBeatmap_MouseDoubleClick(object sender, MouseEventArgs e) {
            if (listNow != null && listNow.SelectedIndices.Count > 0) {
                Beatmap bm = listNow.SelectedItems[0].Tag as Beatmap;
                if (bm != null) {
                    if (bm.SongDir != null)
                        System.Diagnostics.Process.Start(bm.SongDir.FullName);
                    else
                        System.Diagnostics.Process.Start(Config.HttpHost + "/s/" + bm.MapID);
                }
            }
        }
        private void listBeatmap_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) {
            if (!isRunning && listNow != null) {
                Components.ListView lv = listNow;
                this.BeginInvoke(new MethodInvoker(delegate {
                    bool canClear = false, canRestore = false;
                    bool canDownload = lv.SelectedItems.Count > 0;
                    foreach (ListViewItem lvi in lv.SelectedItems) {
                        if (canClear && canRestore && !canDownload)
                            break;
                        Beatmap bm = lvi.Tag as Beatmap;
                        if (bm == null)
                            continue;
                        if (canDownload && GetLocalBeatmap(bm.MapID) != null)
                            canDownload = false;
                        string ch = lvi.SubItems[4].Text;
                        if (!canClear && ch == Config.c_Normal)
                            canClear = (bm.SongDir != null);
                        if (!canRestore && ch == Config.c_Cleared)
                            canRestore = true;
                    }
                    if (toolClear.Enabled != canClear)
                        toolClear.Enabled = toolMenuClear.Enabled = toolStripMenuClear.Enabled = canClear;
                    if (toolRestore.Enabled != canRestore)
                        toolRestore.Enabled = toolMenuRestore.Enabled = toolStripMenuRestore.Enabled = canRestore;
                    if (toolDownload.Enabled != canDownload)
                        toolDownload.Enabled = toolMenuDownload.Enabled = toolStripMenuDownload.Enabled = canDownload;
                }));
                SetStatus(string.Format("选择了 {0} 个谱面", lv.SelectedItems.Count));
            }
        }
        private void listBeatmap_KeyDown(object sender, KeyEventArgs e) {
            if (e.Modifiers == Keys.Control && e.KeyCode == Keys.A)
                toolMenuSelectAll_Click(sender, e);
        }
        private void listBeatmap_GotFocus(object sender, EventArgs e) {
            this.BeginInvoke(new MethodInvoker(delegate {
                bool canClear = false, canRestore = false;
                if (listNow == null)
                    return;
                Components.ListView lv = listNow;
                bool canDownload = lv.SelectedItems.Count > 0;
                foreach (ListViewItem lvi in lv.SelectedItems) {
                    if (canClear && canRestore && !canDownload)
                        break;
                    Beatmap bm = lvi.Tag as Beatmap;
                    if (bm == null)
                        continue;
                    if (canDownload && GetLocalBeatmap(bm.MapID) != null)
                        canDownload = false;
                    string ch = lvi.SubItems[4].Text;
                    if (!canClear && ch == Config.c_Normal)
                        canClear = (bm.SongDir != null);
                    if (!canRestore && ch == Config.c_Cleared)
                        canRestore = true;
                }
                if (toolClear.Enabled != canClear)
                    toolClear.Enabled = toolMenuClear.Enabled = toolStripMenuClear.Enabled = canClear;
                if (toolRestore.Enabled != canRestore)
                    toolRestore.Enabled = toolMenuRestore.Enabled = toolStripMenuRestore.Enabled = canRestore;
                if (toolDownload.Enabled != canDownload)
                    toolDownload.Enabled = toolMenuDownload.Enabled = toolStripMenuDownload.Enabled = canDownload;
            }));
        }
        private void listBeatmap_ColumnClick(object sender, ColumnClickEventArgs e) {
            if (listNow == null)
                return;
            if (e.Column > 3) {
                ListViewImage.SetColumnHeaderSorter(listNow, null);
                return;
            }
            // 0 - 字符串，2 - 日期
            int type = (e.Column == 3 ? 2 : 0);
            SubItemSorter sorter = listNow.ListViewItemSorter as SubItemSorter;
            if (sorter == null) {
                ListViewImage.SetColumnHeaderSorter(listNow, new SubItemSorter(e.Column, false, type));
            } else {
                if (sorter.ColumnIndex == e.Column) {
                    ListViewImage.SetColumnHeaderSorter(listNow, new SubItemSorter(e.Column, !sorter.Asc, sorter.SortType));
                } else {
                    ListViewImage.SetColumnHeaderSorter(listNow, new SubItemSorter(e.Column, false, type));
                }
            }
        }
        private void listBeatmapWeb_MouseWheel(object sender, MouseEventArgs e) {
            if (!isRunning && e.Delta < 0 && listBeatmapWeb.Items.Count > 0) {
                ListViewItem lvi = listBeatmapWeb.Items[listBeatmapWeb.Items.Count - 1];
                if (lvi.Position.Y < listBeatmapWeb.TopItem.Position.Y + listBeatmapWeb.ClientSize.Height)
                    RefreshWeb(int.Parse(listBeatmapWeb.Tag.ToString()) + 1, null);
            }
        }

        private void listDownloader_CancelDownload(object sender, DownloadEventArgs e) {
            Tsanie.OsuDevice.Network.Downloader downloader = e.CurrentDownloadItem.Downloader;
            if (downloader != null) {
                downloader.StopDownload();
                if (downloader.Filename != null) {
                    try {
                        File.Delete(Config.c_AppPath + "\\download\\" + downloader.Filename);
                    } catch (Exception ex) {
                        MessageBox.Show(this, "无法删除源文件，" + ex.Message, "取消下载", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                }
            }
            listDownloader.RemoveDownload(e.CurrentDownloadItem);
            bool flag = false;
            foreach (DownloadItem di in listDownloader.DownloadItems) {
                flag |= di.DownloadState == DownloadState.Downloading;
            }
            if (!flag)
                TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
            SetStatus(string.Format("一共 {0} 个下载任务", listDownloader.DownloadItems.Count));
        }
        private void listDownloader_ItemMouseDown(object sender, DownloadMouseEventArgs e) {
            if (e.CurrentDownloaditem.DownloadState == DownloadState.Done) {
                toolDownloaderMenuOpen.Enabled = true;
            } else {
                toolDownloaderMenuOpen.Enabled = false;
            }
        }
        private void toolDownloaderMenuOpen_Click(object sender, EventArgs e) {
            DownloadItem item = listDownloader.CurrentDownloadItem;
            new Thread(() => {
                DirectoryInfo outDir = Directory.CreateDirectory(Config.OsuPath + @"\Songs\"
                    + Path.GetFileNameWithoutExtension(item.Downloader.Filename));
                try {
                    using (ZipInputStream zip = new ZipInputStream(File.OpenRead(item.Downloader.FilePath))) {
                        ZipEntry entry;
                        while ((entry = zip.GetNextEntry()) != null) {
                            if (entry.IsDirectory) {
                                string dirName = Path.GetDirectoryName(entry.Name);
                                if (dirName != null && dirName.Length > 0) {
                                    Directory.CreateDirectory(outDir.FullName + "\\" + dirName);
                                }
                            } else if (entry.IsFile) {
                                string file = outDir.FullName + "\\" + entry.Name;
                                string path = Path.GetDirectoryName(file);
                                if (!Directory.Exists(path))
                                    Directory.CreateDirectory(path);
                                string ext = Path.GetExtension(file).ToLower();
                                if (ext == ".jpg" || ext == ".png") {
                                    file += ".bak";
                                }
                                using (FileStream fs = File.Create(file)) {
                                    byte[] buffer = new byte[2048];
                                    int n;
                                    while ((n = zip.Read(buffer, 0, buffer.Length)) > 0) {
                                        fs.Write(buffer, 0, n);
                                    }
                                }
                            }
                        }
                    }
                    // 解压完毕
                    Util.ThreadSafeRun(this, delegate {
                        ListViewItem lvi = item.OwnerItem;
                        Beatmap bm = null;
                        if (lvi != null) {
                            lvi.Remove();
                            bm = lvi.Tag as Beatmap;
                        } else {
                            bm = new Beatmap() {
                                Title = item.FileName,
                                MapID = item.Downloader.BeatmapID
                            };
                        }
                        lvi = BeatmapUtil.CreateListViewItem(bm);
                        DirectoryInfo song = outDir;
                        bm.SongDir = song;
                        bm.Date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        listBeatmapLocal.Items.Add(lvi);
                        new Thread(new ParameterizedThreadStart(MoreActive)) { Name = "threadMoreActive_" + bm.MapID }.Start(lvi);
                        new Thread(() => {
                            BeatmapUtil.ReadBeatmapInfo(lvi, bm.SongDir, this, true);
                            Util.ThreadSafeRun(this, delegate {
                                listBeatmapLocal.SelectedItems.Clear();
                                lvi.Selected = true;
                                lvi.Focused = true;
                                listBeatmapLocal.Sort();
                                lvi.EnsureVisible();
                            });
                        }) { Name = "threadReadBeatmapInfo_" + bm.MapID }.Start();
                        TreeNode node = treeNagetive.Nodes["nodeLibrary"].Nodes["nodeLibraryLocal"];
                        treeNagetive.SelectedNode = node;
                        treeNagetive_AfterSelect(sender, new TreeViewEventArgs(node, TreeViewAction.ByMouse));

                        // Web缓存列表移除相应谱面
                        StreamWriter writer = new StreamWriter(Config.c_AppPath + "\\beatmapswebtmp.txt", false, Encoding.UTF8);
                        foreach (ListViewItem lviWeb in listBeatmapWeb.Items) {
                            writer.WriteLine(lviWeb.Tag);
                        }
                        writer.WriteLine(listBeatmapWeb.Tag);
                        writer.Flush();
                        writer.Close();
                        writer.Dispose();
                        SetStatus("解压完毕！");
                    });
                } catch (Exception ex) {
                    LogUtil.Error(ex, (ex2) => {
                        Util.ThreadSafeRun(this, delegate {
                            MessageBox.Show(this, "解压Beatmap文件出现错误！" + ex2.Message, "解压", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        });
                    });
                }
            }) { Name = "threadUnzipBeatmap" }.Start();
        }
        private void toolComboSearch_KeyUp(object sender, KeyEventArgs e) {
            if (e.Modifiers == Keys.None && e.KeyCode == Keys.Enter) {
                TreeNode node = null;
                string s = toolComboSearch.Text;
                if (s.StartsWith("s/") || s.StartsWith("b/")) {
                    if (s.Length < 3) {
                        goto other;
                    }
                    string outDir = Config.c_AppPath + "\\download";
                    if (!Directory.Exists(outDir))
                        Directory.CreateDirectory(outDir);
                    DownloadItem item = listDownloader.AddDownload(s, null);
                    HttpHelper.BeginConnect(Config.HttpHost + "/" + s, (request) => {
                        request.Headers["Cookie"] = Config.Cookies;
                    }, (state) => {
                        string id = null;
                        using (StreamReader reader = new StreamReader(state.StreamResponse)) {
                            string line;
                            while ((line = reader.ReadLine()) != null) {
                                int index = line.IndexOf("<title>osu! - ");
                                if (index >= 0) {
                                    line = line.Substring(index + 14);
                                    line = line.Substring(0, line.IndexOf('<'));
                                    item.FileName = line;
                                    //continue;
                                }
                                index = line.IndexOf("beatmap-update.php?s=");
                                if (index >= 0) {
                                    line = line.Substring(index + 21);
                                    line = line.Substring(0, line.IndexOf('&'));
                                    id = line;
                                    break;
                                }
                            }
                        }
                        if (id == null) {
                            throw new Exception("无法获取谱面ID！请尝试登录后再试。");
                        }
                        DownloadBeatmap(id, item, outDir);
                    }, (ex) => {
                        Util.ThreadSafeRun(this, delegate {
                            MessageBox.Show(this, "下载时出现错误！" + ex.Message, "下载", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            item.DownloadState = DownloadState.Paused;
                            if (totalLength <= 0)
                                TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
                        });
                    });
                    node = treeNagetive.Nodes["nodeManager"].FirstNode;
                    treeNagetive.SelectedNode = node;
                    treeNagetive_AfterSelect(sender, new TreeViewEventArgs(node, TreeViewAction.ByMouse));
                    TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_INDETERMINATE);
                    return;
                }
            other:
                node = treeNagetive.Nodes["nodeLibrary"].Nodes["nodeLibraryWeb"];
                treeNagetive.SelectedNode = node;
                treeNagetive_AfterSelect(sender, new TreeViewEventArgs(node, TreeViewAction.ByMouse));
                menuRefresh_Click(sender, null);
            }
        }

        private void toolMenuClear_Click(object sender, EventArgs e) {
            if (listNow == null || listNow != listBeatmapLocal)
                return;
            isRunning = true;
            int max = listBeatmapLocal.SelectedItems.Count;
            int n = 0;
            EnabledControl(false);
            TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NORMAL);
            TaskbarExt.SetValue(taskbarItem, this, 0, max);
            this.BeginInvoke(new MethodInvoker(delegate {
                bool flag = true;
                for (int i = 0; i < listBeatmapLocal.SelectedItems.Count; i++) {
                    if (!isRunning)
                        return;
                    ListViewItem lvi = listBeatmapLocal.SelectedItems[i];
                    if (lvi.SubItems[4].Text == Config.c_Cleared)
                        continue;
                    Beatmap bm = (Beatmap)lvi.Tag;
                    if (flag &= ClearPath(bm.SongDir)) {
                        lvi.SubItems[4].Text = Config.c_Cleared;
                        n++;
                    }
                    TaskbarExt.SetValue(taskbarItem, this, i, max);
                }
                TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
                SetStatus(string.Format("就绪...本地一共 {0} 张谱面, 清理了 {1} 张谱面" + (flag ? "" : "，有些谱面未完成清理"), listBeatmapLocal.Items.Count, n), false);
                EnabledControl(true);
                EnabledRefresh(true);
                isRunning = false;
                listBeatmap_ItemSelectionChanged(sender, null);
            }));
        }
        private void toolMenuRestore_Click(object sender, EventArgs e) {
            if (listNow == null || listNow != listBeatmapLocal)
                return;
            isRunning = true;
            int max = listBeatmapLocal.SelectedItems.Count;
            int n = 0;
            EnabledControl(false);
            TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NORMAL);
            TaskbarExt.SetValue(taskbarItem, this, 0, max);
            this.BeginInvoke(new MethodInvoker(delegate {
                bool flag = true;
                for (int i = 0; i < listBeatmapLocal.SelectedItems.Count; i++) {
                    if (!isRunning)
                        break;
                    ListViewItem lvi = listBeatmapLocal.SelectedItems[i];
                    if (lvi.SubItems[4].Text == Config.c_Normal)
                        continue;
                    Beatmap bm = (Beatmap)lvi.Tag;
                    if (flag &= RestorePath(bm.SongDir)) {
                        lvi.SubItems[4].Text = Config.c_Normal;
                        n++;
                    }
                    TaskbarExt.SetValue(taskbarItem, this, i, max);
                }
                TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
                SetStatus(string.Format("就绪...本地一共 {0} 张谱面, 恢复了 {1} 张谱面" + (flag ? "" : "，有些谱面未完成恢复"), listBeatmapLocal.Items.Count, n), false);
                EnabledControl(true);
                EnabledRefresh(true);
                isRunning = false;
                listBeatmap_ItemSelectionChanged(sender, null);
            }));
        }
        private void toolMenuSelectClear_Click(object sender, EventArgs e) {
            if (listNow == null || listNow != listBeatmapLocal)
                return;
            isRunning = true;
            listBeatmapLocal.SelectedItems.Clear();
            bool flag = true;
            foreach (ListViewItem lvi in listBeatmapLocal.Items) {
                if (lvi.SubItems[4].Text != Config.c_Cleared) {
                    if (flag) {
                        lvi.Focused = true;
                        lvi.EnsureVisible();
                        flag = false;
                    }
                    lvi.Selected = true;
                }
            }
            isRunning = false;
            listBeatmap_ItemSelectionChanged(sender, null);
        }
        private void toolMenuSelectAll_Click(object sender, EventArgs e) {
            if (listNow == null)
                return;
            isRunning = true;
            foreach (ListViewItem lvi in listNow.Items)
                lvi.Selected = true;
            isRunning = false;
            listBeatmap_ItemSelectionChanged(sender, null);
        }
        private void toolMenuSelectNot_Click(object sender, EventArgs e) {
            if (listNow == null)
                return;
            isRunning = true;
            foreach (ListViewItem lvi in listNow.Items)
                lvi.Selected = false;
            isRunning = false;
            listBeatmap_ItemSelectionChanged(sender, null);
        }
        private void toolMenuSelectRevert_Click(object sender, EventArgs e) {
            if (listNow == null)
                return;
            isRunning = true;
            bool flag = true;
            foreach (ListViewItem lvi in listNow.Items) {
                lvi.Selected = !lvi.Selected;
                if (flag && lvi.Selected) {
                    lvi.Focused = true;
                    lvi.EnsureVisible();
                    flag = false;
                }
            }
            isRunning = false;
            listBeatmap_ItemSelectionChanged(sender, null);
        }

        private void treeNagetive_AfterSelect(object sender, TreeViewEventArgs e) {
            if (e.Action == TreeViewAction.ByMouse) {
                switch (e.Node.Name) {
                    case "nodeLibraryLocal":
                        listBeatmapWeb.Visible = false;
                        listBeatmapLocal.Visible = true;
                        listDownloader.Visible = false;
                        listNow = listBeatmapLocal;
                        if (listBeatmapLocal.Items.Count == 0)
                            RefreshLocal("\\beatmaps.txt", listBeatmapLocal);
                        SetStatus(string.Format("本地一共 {0} 张谱面", listBeatmapLocal.Items.Count));
                        break;
                    case "nodeLibraryWeb":
                        listBeatmapLocal.Visible = false;
                        listBeatmapWeb.Visible = true;
                        listDownloader.Visible = false;
                        listNow = listBeatmapWeb;
                        if (listBeatmapWeb.Items.Count == 0)
                            RefreshLocal("\\beatmapswebtmp.txt", listBeatmapWeb);
                        SetStatus(string.Format("一共搜索到 {0} 张谱面", listBeatmapWeb.Items.Count));
                        break;
                    case "nodeDownload":
                        listBeatmapLocal.Visible = false;
                        listBeatmapWeb.Visible = false;
                        listDownloader.Visible = true;
                        listNow = null;
                        SetStatus(string.Format("一共 {0} 个下载任务", listDownloader.DownloadItems.Count));
                        break;
                }
            }
        }
        private void treeNagetive_GotFocus(object sender, EventArgs e) {
            if (listBeatmapLocal.Visible)
                listBeatmapLocal.Focus();
            else if (listBeatmapWeb.Visible)
                listBeatmapWeb.Focus();
            else if (listDownloader.Visible)
                listDownloader.Focus();
        }
        #endregion

        private bool ClearPath(DirectoryInfo di) {
            if (di == null)
                return false;
            bool flag = false;
            foreach (FileInfo fi in di.GetFiles()) {
                string ext = fi.Extension.ToLower();
                if (ext == ".jpg" || ext == ".png") {
                    try {
                        File.Delete(fi.FullName + ".bak");
                        fi.MoveTo(fi.FullName + ".bak");
                        flag = true;
                    } catch (Exception ex) {
                        LogUtil.Error(ex, null);
                        MessageBox.Show(this, "清理出错！" + ex.Message, "清理", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                }
            }
            foreach (DirectoryInfo d in di.GetDirectories()) {
                flag |= ClearPath(d);
            }
            return flag;
        }
        private bool RestorePath(DirectoryInfo di) {
            if (di == null)
                return false;
            bool flag = false;
            foreach (FileInfo fi in di.GetFiles("*.bak", SearchOption.TopDirectoryOnly)) {
                string newFile = fi.FullName.Substring(0, fi.FullName.Length - 4);
                try {
                    File.Delete(newFile);
                    fi.MoveTo(newFile);
                    flag = true;
                } catch (Exception ex) {
                    LogUtil.Error(ex, null);
                    MessageBox.Show(this, "恢复出错！" + ex.Message, "恢复", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
            }
            foreach (DirectoryInfo d in di.GetDirectories()) {
                flag |= RestorePath(d);
            }
            return flag;
        }
        internal void EnabledControl(bool enabled) {
            toolLogin.Enabled = toolMenuLogin.Enabled = enabled && Config.Cookies == null;
            toolLogout.Enabled = toolMenuLogout.Enabled = enabled && Config.Cookies != null;
            toolOption.Enabled = toolMenuOption.Enabled = enabled;
            if (!enabled)
                toolRefresh.Enabled = toolMenuRefresh.Enabled = enabled;
            bool canClear = false, canRestore = false;
            bool canDownload = false;
            if (listNow != null) {
                Components.ListView lv = listNow;
                canDownload = lv.SelectedItems.Count > 0;
                foreach (ListViewItem lvi in lv.SelectedItems) {
                    if (canClear && canRestore && !canDownload)
                        break;
                    string ch = lvi.SubItems[4].Text;
                    if (!canClear && ch == Config.c_Normal)
                        canClear = true;
                    if (!canRestore && ch == Config.c_Cleared)
                        canRestore = true;
                    if (canDownload) {
                        Beatmap bm = lvi.Tag as Beatmap;
                        if (bm != null && GetLocalBeatmap(bm.MapID) != null)
                            canDownload = false;
                    }
                }
            }
            toolClear.Enabled = toolMenuClear.Enabled = toolStripMenuClear.Enabled = enabled && canClear;
            toolRestore.Enabled = toolMenuRestore.Enabled = toolStripMenuRestore.Enabled = enabled && canRestore;
            toolDownload.Enabled = toolMenuDownload.Enabled = toolStripMenuDownload.Enabled = enabled && canDownload;
            bool canSelect = enabled && (listNow != null);
            toolMenuSelectAll.Enabled = toolStripMenuSelectAll.Enabled = canSelect;
            toolMenuSelectClear.Enabled = toolStripMenuSelectClear.Enabled = canSelect;
            toolMenuSelectNot.Enabled = canSelect;
            toolMenuSelectRevert.Enabled = canSelect;
        }
        internal void EnabledRefresh(bool enabled) {
            toolRefresh.Enabled = toolMenuRefresh.Enabled = enabled;
        }
        internal void SetStatus(string text, bool loading) {
            if (toolStatusLoading.Visible != loading)
                toolStatusLoading.Visible = loading;
            SetStatus(text);
        }
        internal void SetStatus(string text) {
            toolStatus.Text = text;
        }

        private bool RefreshLocal(string file, Tsanie.OsuDevice.Components.ListView list) {
            // 载入谱面列表缓存文件
            if (!File.Exists(Config.c_AppPath + file))
                return false;
            // 开始分析
            isRunning = true;
            if (!Directory.Exists(Config.c_AppPath + "\\bgs"))
                Directory.CreateDirectory(Config.c_AppPath + "\\bgs");
            EnabledControl(false);
            list.Items.Clear();
            System.Collections.IComparer sorter = list.ListViewItemSorter;
            ListViewImage.SetColumnHeaderSorter(list, null);
            SetStatus("正在加载谱面...请稍候", true);
            Application.DoEvents();
            new Thread(() => {
                Util.ThreadSafeRun(this, delegate { TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_INDETERMINATE); });
                StreamReader reader = new StreamReader(Config.c_AppPath + file, Encoding.UTF8);
                string line;
                while (isRunning && (line = reader.ReadLine()) != null) {
                    Beatmap bm = Beatmap.Parse(line);
                    if (bm == null) {
                        int i;
                        if (listNow == listBeatmapWeb && int.TryParse(line, out i)) {
                            listBeatmapWeb.Tag = i;
                        }
                        continue;
                    }
                    ListViewItem lvi = BeatmapUtil.CreateListViewItem(bm);
                    ThreadPool.QueueUserWorkItem(new WaitCallback(MoreActive), lvi);
                    Util.ThreadSafeRun(this, delegate { list.Items.Add(lvi); });
                }
                reader.Close();
                reader.Dispose();
                isRunning = false;
                Util.ThreadSafeRun(this, delegate {
                    ListViewImage.SetColumnHeaderSorter(list, sorter as SubItemSorter);
                    TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
                    EnabledControl(true);
                    EnabledRefresh(true);
                    SetStatus(string.Format("就绪...一共 {0} 张谱面", list.Items.Count), false);
                    list.Focus();
                });
            }) { Name = "refreshLocal_" + list.Name }.Start();
            return true;
        }
        private void Refresher() {
            DirectoryInfo osuDir = new DirectoryInfo(Config.OsuPath + @"\Songs");
            if (!osuDir.Exists) {
                MessageBox.Show(this, "Osu谱面文件夹不存在！", "Osu谱面文件夹", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            isRunning = true;
            if (!Directory.Exists(Config.c_AppPath + "\\bgs"))
                Directory.CreateDirectory(Config.c_AppPath + "\\bgs");
            listBeatmapLocal.Items.Clear();
            System.Collections.IComparer sorter = listBeatmapLocal.ListViewItemSorter;
            ListViewImage.SetColumnHeaderSorter(listBeatmapLocal, null);
            SetStatus("正在加载谱面...请稍候", true);
            EnabledControl(false);
            new Thread(() => {
                BeatmapUtil.ResetLocalReaded();
                DirectoryInfo[] songs = osuDir.GetDirectories();
                Util.ThreadSafeRun(this, delegate {
                    TaskbarExt.SetValue(taskbarItem, this, 0, songs.Length);
                    TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NORMAL);
                });
                for (int i = 0; i < songs.Length; i++) {
                    DirectoryInfo song = songs[i];
                    Beatmap bm = new Beatmap();
                    bm.SongDir = song;
                    bm.Date = song.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss");
                    // 获取beatmap的ID
                    foreach (char c in song.Name) {
                        if (c >= '0' && c <= '9')
                            bm.MapID += c;
                        else
                            break;
                    }
                    if (bm.MapID == null) {
                        bm.MapID = "(" + DateTime.Now.Ticks + ")";
                        LogUtil.Error(new Exception("MapID获取失败, " + song.FullName), null);
                        continue;
                    }
                    string name = song.Name.Substring(bm.MapID.Length + 1);
                    int index = name.IndexOf(" - ");
                    if (index > 0) {
                        bm.Artist = name.Substring(0, index);
                    } else {
                        index = name.IndexOf("_-_");
                        if (index > 0) {
                            bm.Artist = name.Substring(0, index);
                        }
                    }
                    name = name.Substring(bm.Artist.Length + 3);
                    bm.Artist = bm.Artist.Trim(new char[] { '_', ' ' });
                    bm.Title = name.Trim(new char[] { '_', ' ' });
                    ListViewItem lvi = BeatmapUtil.CreateListViewItem(bm);
                    ThreadPool.QueueUserWorkItem(new WaitCallback(MoreActive), lvi);
                    ThreadPool.QueueUserWorkItem(new WaitCallback((obj) => { BeatmapUtil.ReadBeatmapInfo(lvi, song, this, false); }), null);
                    Util.ThreadSafeRun(this, delegate {
                        listBeatmapLocal.Items.Add(lvi);
                        TaskbarExt.SetValue(taskbarItem, this, i, songs.Length);
                    });
                }
                Util.ThreadSafeRun(this, delegate {
                    ListViewImage.SetColumnHeaderSorter(this.listBeatmapLocal, sorter as SubItemSorter);
                    TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
                    SetStatus(string.Format("就绪...本地一共 {0} 张谱面", songs.Length), false);
                    EnabledControl(true);
                });
            }) { Name = "threadBeatmapRefresher" }.Start();
        }
        private void RefreshWeb() {
            isRunning = true;
            if (!Directory.Exists(Config.c_AppPath + "\\bgs"))
                Directory.CreateDirectory(Config.c_AppPath + "\\bgs");
            listBeatmapWeb.Items.Clear();
            System.Collections.IComparer sorter = listBeatmapWeb.ListViewItemSorter;
            ListViewImage.SetColumnHeaderSorter(listBeatmapWeb, null);
            File.Delete(Config.c_AppPath + "\\beatmapswebtmp.txt");
            RefreshWeb(1, sorter);
        }
        private void RefreshWeb(int page, System.Collections.IComparer sorter) {
            if (page <= 0)
                return;
            isRunning = true;
            int type = 0;
            switch (toolComboType.SelectedIndex) {
                case 1:
                    type = 6;
                    break;
                case 2:
                    type = 2;
                    break;
                case 3:
                    type = 5;
                    break;
                case 4:
                    type = 4;
                    break;
            }
            listBeatmapWeb.Tag = page;
            SetStatus("正在下载谱面列表...请稍候", true);
            EnabledControl(false);
            TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_INDETERMINATE);
            HttpHelper.BeginConnect(Config.HttpHost + "/p/beatmaplist?s=4&o=1&q="
                + HttpUtility.UrlEncode(toolComboSearch.Text)
                + "&r=" + type
                + "&page=" + page, (request) => {
                    // 关键字，类型，Rank时间排序，倒序
                    //request.Headers["Pragma"] = "no-cache";
                    request.Headers["Cache-Control"] = "max-age=0";
                    request.Headers["Cookie"] = Config.Cookies;
                }, (state) => {
                    using (StreamReader reader = new StreamReader(state.StreamResponse)) {
                        StreamWriter writer = new StreamWriter(Config.c_AppPath + "\\beatmapswebtmp.txt", true, Encoding.UTF8);
                        string line;
                        while ((line = reader.ReadLine()) != null) {
                            if (line.StartsWith("<tr class='row")) {
                                line = line.Substring(line.IndexOf("expandRow(") + 10);
                                string id = line.Substring(0, line.IndexOf(')'));
                                if (GetLocalBeatmap(id) != null)
                                    continue;
                                Beatmap bm = new Beatmap();
                                bm.MapID = id;
                                string link = "<a href='/s/" + bm.MapID + "'>";
                                line = line.Substring(line.IndexOf(link) + link.Length);
                                bm.Title = line.Substring(0, line.IndexOf("</a>"));
                                link = "<td onclick='load(" + bm.MapID + ",event)'>";
                                line = line.Substring(line.IndexOf(link) + link.Length);
                                bm.Artist = line.Substring(0, line.IndexOf('<'));
                                link = "<div class='listing-src'>";
                                int index = line.IndexOf(link);
                                if (index < 0)
                                    bm.Source = "";
                                else {
                                    line = line.Substring(index + link.Length);
                                    bm.Source = line.Substring(0, line.IndexOf('<')).Trim(new char[] { '(', ')' });
                                }
                                link = "<a href='/u/";
                                line = line.Substring(line.IndexOf(link) + link.Length);
                                line = line.Substring(line.IndexOf("'>") + 2);
                                bm.Creator = line.Substring(0, line.IndexOf("</a>"));
                                link = "width=96>";
                                line = line.Substring(line.IndexOf(link) + link.Length);
                                //TODO:
                                string difficulity = line.Substring(0, line.IndexOf("</td>"));
                                bm.Versions = new string[0];
                                link = ",event)'>";
                                line = line.Substring(line.IndexOf(link) + link.Length);
                                bm.Date = line.Substring(0, line.IndexOf('<')); // br/>
                                bm.SongDir = GetLocalBeatmap(bm.MapID);
                                writer.WriteLine(bm.ToString());
                                ListViewItem lvi = BeatmapUtil.CreateListViewItem(bm);
                                ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadPhoto), lvi);
                                Util.ThreadSafeRun(this, delegate { listBeatmapWeb.Items.Add(lvi); });
                            }
                        }
                        writer.WriteLine(page);
                        writer.Flush();
                        writer.Close();
                        writer.Dispose();
                        reader.Close();
                        reader.Dispose();
                        Util.ThreadSafeRun(this, delegate {
                            if (sorter != null) {
                                ListViewImage.SetColumnHeaderSorter(listBeatmapWeb, sorter as SubItemSorter);
                            }
                            TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
                            SetStatus(string.Format("就绪...一共搜索到 {0} 张谱面", listBeatmapWeb.Items.Count), false);
                            EnabledControl(true);
                            EnabledRefresh(true);
                        });
                        isRunning = false;
                    }
                }, (ex) => {
                    Util.ThreadSafeRun(this, delegate {
                        MessageBox.Show(this, "读取谱面列表失败！请检查网络环境。", "Beatmaps 站点", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
                        SetStatus("读取谱面列表失败！请检查网络环境。", false);
                        EnabledControl(true);
                        EnabledRefresh(true);
                    });
                    isRunning = false;
                });
        }

        private DirectoryInfo GetLocalBeatmap(string mapID) {
            if (string.IsNullOrEmpty(mapID))
                return null;
            DirectoryInfo osuDir = new DirectoryInfo(Config.OsuPath + @"\Songs");
            if (!osuDir.Exists)
                return null;
            DirectoryInfo rtn = null;
            foreach (DirectoryInfo di in osuDir.GetDirectories(mapID + "*", SearchOption.TopDirectoryOnly)) {
                if (di.Name.Length > mapID.Length) {
                    char c = di.Name[mapID.Length];
                    if (c < '0' || c > '9') {
                        rtn = di;
                        break;
                    }
                }
            }
            return rtn;
        }
        private void DownloadPhoto(object lviObj) {
            ListViewItem lvi = (ListViewItem)lviObj;
            Beatmap bm = (Beatmap)lvi.Tag;
            //// 判断是否可以清理或否
            //if (bm.SongDir != null && bm.SongDir.GetFiles("*.bak", SearchOption.TopDirectoryOnly).Length > 0) {
            //    // 可以恢复
            //    Util.ThreadSafeRun(this, delegate { lvi.SubItems[4].Text = Config.c_Cleared; });
            //}
            bool flag = false;
            Util.ThreadSafeRun(this, delegate {
                if (imageList.Images.ContainsKey(bm.MapID)) {
                    lvi.ImageKey = bm.MapID;
                    flag = true;
                }
            });
            if (flag)
                return;

            string bgFile = Config.c_AppPath + "\\bgs\\" + bm.MapID + ".jpg";
            Image image = null;
            // 如果存在缓存图就载入
            if (File.Exists(bgFile)) {
                image = Image.FromFile(bgFile);
                Util.ThreadSafeRun(this, delegate {
                    imageList.Images.Add(bm.MapID, image);
                    lvi.ImageKey = bm.MapID;
                });
            } else {
                // 下载图片
                HttpHelper.BeginConnect("http://d.osu.ppy.sh/mt/" + bm.MapID, (request) => {
                    request.Headers["Pragma"] = "no-cache";
                    request.Headers["Cache-Control"] = "no-cache";
                    request.Headers["Cookie"] = Config.Cookies;
                }, (state) => {
                    image = Image.FromStream(state.StreamResponse);
                    image.Save(bgFile, System.Drawing.Imaging.ImageFormat.Jpeg);
                    Util.ThreadSafeRun(this, delegate {
                        lock (imageList) {
                            imageList.Images.Add(bm.MapID, image);
                        }
                        lvi.ImageKey = bm.MapID;
                    });
                }, (ex) => {
                    lvi.ImageKey = "none";
#if DEBUG
                    Console.WriteLine("DownloadPhoto - 下载图片失败!");
#endif
                });
            }
        }
        private void MoreActive(object lviObj) {
            ListViewItem lvi = (ListViewItem)lviObj;
            Beatmap bm = (Beatmap)lvi.Tag;
            // 判断是否可以清理或否
            if (bm.SongDir != null && bm.SongDir.Exists && bm.SongDir.GetFiles("*.bak", SearchOption.TopDirectoryOnly).Length > 0) {
                // 可以恢复
                Util.ThreadSafeRun(this, delegate { lvi.SubItems[4].Text = Config.c_Cleared; });
            }

            // 载入图片
            bool flag = false;
            Util.ThreadSafeRun(this, delegate {
                if (imageList.Images.ContainsKey(bm.MapID)) {
                    lvi.ImageKey = bm.MapID;
                    flag = true;
                }
            });
            if (flag)
                return;

            string bgFile = Config.c_AppPath + "\\bgs\\" + bm.MapID + ".jpg";
            Image image = null;
            // 如果存在缓存图就载入
            if (File.Exists(bgFile)) {
                image = Image.FromFile(bgFile);
            } else if (bm.SongDir != null) {
                foreach (FileInfo fi in bm.SongDir.GetFiles("*.osu", SearchOption.TopDirectoryOnly)) {
                    StreamReader reader = new StreamReader(fi.OpenRead(), true);
                    string line;
                    bool isTaiko = false;
                    while ((line = reader.ReadLine()) != null) {
                        if (!isTaiko && line.StartsWith("Mode:")) {
                            isTaiko = (line.Substring(5).Trim() == "1");
                        }
                        // 没有缓存图片
                        if (!isTaiko && line.StartsWith("0,0,\"")) {
                            line = line.Substring(5).Trim(new char[] { ' ', '\"' }).ToLower();
                            if (line.EndsWith(".jpg") || line.EndsWith(".png") || line.EndsWith(".bmp")) {
                                // 找到图片
                                try {
                                    string photoName = bm.SongDir.FullName + "\\" + line;
                                    if (File.Exists(photoName) || File.Exists(photoName = photoName + ".bak")) {
                                        image = new Bitmap(Image.FromFile(photoName), 80, 60);
                                        image.Save(bgFile, System.Drawing.Imaging.ImageFormat.Jpeg);
                                        break;
                                    }
                                } catch {
#if DEBUG
                                    Console.WriteLine("menuRefresh_Click - Image.FromFile(...) Error!");
#endif
                                }
                            }
                        }
                    }
                    reader.Close();
                }
            }
            if (image != null) {
                Util.ThreadSafeRun(this, delegate {
                    lock (imageList) {
                        imageList.Images.Add(bm.MapID, image);
                    }
                    lvi.ImageKey = bm.MapID;
                });
            } else {
                Util.ThreadSafeRun(this, delegate { lvi.ImageKey = "none"; });
            }
        }

        private void DownloadBeatmap(string beatmapID, DownloadItem item, string outDir) {
            Tsanie.OsuDevice.Network.Downloader dl = new Network.Downloader() {
                BeatmapID = beatmapID,
                OutFolder = outDir,
                RequestBefore = null,
                ReadInfo = (filename, length) => {
                    item.FileName = filename;
                    item.TotalSize = length;
                    totalLength += length;
                    if (item.Downloader.CanPause)
                        item.FileIcon = Tsanie.OsuDevice.Properties.Resources.osz;
                    Util.ThreadSafeRun(this, delegate {
                        TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NORMAL);
                        TaskbarExt.SetValue(taskbarItem, this, 0, totalLength);
                    });
                },
                ReceiveFunc = (received, timeSpan) => {
                    item.CurrentSize = received;
                    item.Speed = (int)(received / timeSpan.TotalSeconds);
                    int count = 0;
                    foreach (DownloadItem di in listDownloader.DownloadItems) {
                        if (di.DownloadState == DownloadState.Downloading)
                            count += di.Downloader.FileReceived;
                    }
                    Util.ThreadSafeRun(this, delegate {
                        TaskbarExt.SetValue(taskbarItem, this, count, totalLength);
                    });
                },
                DoneFunc = (length) => {
                    item.DownloadState = DownloadState.Done;
                    item.BrowserClick += (sender, e) => { System.Diagnostics.Process.Start(outDir); };
                    totalLength -= item.Downloader.FileLength;
                    if (totalLength <= 0) {
                        Util.ThreadSafeRun(this, delegate {
                            TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
                        });
                    }
                },
                ExceptionFunc = (ex) => {
                    Util.ThreadSafeRun(this, delegate {
                        MessageBox.Show(this, ex.Message, "下载", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        //item.CurrentSize = 0;
                        item.Downloader.PauseDownload();
                        item.DownloadState = DownloadState.Paused;
                        totalLength -= item.Downloader.FileLength;
                        if (totalLength <= 0)
                            TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
                    });
                }
            };
            item.Downloader = dl;
            item.PauseClick += (sender, e) => {
                if (item.Downloader.CanPause || MessageBox.Show(this, "从Osu主站下载，最好不要轻易暂停，是否确认暂停？", "暂停下载",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) {
                    dl.PauseDownload();
                    item.DownloadState = DownloadState.Paused;
                    totalLength -= item.Downloader.FileLength;
                    if (totalLength <= 0)
                        TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NOPROGRESS);
                }
            };
            item.ResumeClick += (sender, e) => {
                dl.ResumeDownload();
                item.DownloadState = DownloadState.Downloading;
                totalLength += item.Downloader.FileLength;
                if (totalLength > 0) {
                    TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_NORMAL);
                } else {
                    TaskbarExt.SetState(taskbarItem, this, TBPFLAG.TBPF_INDETERMINATE);
                }
            };
            dl.StartDownload();
        }
    }
}
